/**
 * Copyright (C), 2020, 中电科新型智慧城市研究院有限公司
 * FileName: ElUtils
 * Author:   YHY
 * Date:     2020-7-28 10:40
 * Description:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package utils;

import cn.hutool.core.util.StrUtil;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.*;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.Assert;

import java.util.Map;
import java.util.Objects;

/**
 * 〈一句话功能简述〉<br>
 * 〈spring el 表达式 工具类〉
 *
 * @author yhy
 * @create 2020-7-28
 * @since 1.0.0
 */
public class ElUtils {

    /**
     * 功能描述: <br>
     * 〈将模板解析成表达式对象，使用默认的表达式占位方式${}〉
     *
     * @param template
     * @return:org.springframework.expression.Expression
     * @Author:yanghongyuan
     * @Date: 2020-7-28 10:54
     */
    public static Expression parse(String template) {

        if (Objects.isNull(template)) {
            throw new RuntimeException("el表达式解析失败，模板为null");
        }

        TemplateParserContext templateParserContext = new TemplateParserContext("${", "}");
        ExpressionParser parser = new SpelExpressionParser();
        return parser.parseExpression(template, templateParserContext);
    }

    /**
     * 功能描述: <br>
     * 〈将模板解析成表达式对象，使用默认的表达式占位前缀和后缀〉示例 #{}
     *
     * @param template
     * @param expressionPrefix #{
     * @param expressionSuffix }
     * @return:org.springframework.expression.Expression
     * @Author:yanghongyuan
     * @Date: 2020-7-28 10:55
     */
    public static Expression parse(String template, String expressionPrefix, String expressionSuffix) {

        if (Objects.isNull(template)) {
            throw new RuntimeException("el表达式解析失败，模板为null");
        }

        if (StrUtil.isBlank(expressionPrefix) || StrUtil.isBlank(expressionSuffix)) {
            throw new RuntimeException("el表达式解析失败，表达式前缀或后缀为空");
        }

        TemplateParserContext templateParserContext = new TemplateParserContext(expressionPrefix, expressionSuffix);
        ExpressionParser parser = new SpelExpressionParser();
        return parser.parseExpression(template, templateParserContext);
    }

   /**
    * 功能描述: <br>
    * 〈使用数据对象生成表达式上下文〉
    *
    * @param rootObject 数据实体
    * @param mapAccessor 是否将map映射为普通类访问方式；映射前访问map字段：a[b]，映射后访问map字段：a.b
    * @return:org.springframework.expression.EvaluationContext
    * @Author:yanghongyuan
    * @Date: 2020-7-28 10:57
    */
    public static EvaluationContext context(Object rootObject, boolean mapAccessor) {
        StandardEvaluationContext evaluationContext = new StandardEvaluationContext(rootObject);
        if (mapAccessor) {
            evaluationContext.addPropertyAccessor(new MapAccessor());
        }
        return evaluationContext;
    }

    /**
     * 功能描述: <br>
     * 〈直接将模板中的占位符使用数据对象中的数据填充并返回，占位符格式${}〉
     *
     * @param template
     * @param rootObject
     * @return:java.lang.Object
     * @Author:yanghongyuan
     * @Date: 2020-7-28 10:59
     */
    public static Object fillTemplate(String template, Object rootObject) {
        Expression parse = parse(template);
        EvaluationContext context = context(rootObject, true);
        return parse.getValue(context);
    }

    /**
     * 功能描述: <br>
     * （直接将模板中的占位符使用数据对象中的数据填充并返回，占位符格式为自定义〉
     *
     * @param template
     * @param expressionPrefix
     * @param expressionSuffix
     * @param rootObject
     * @return:java.lang.Object
     * @Author:yanghongyuan
     * @Date: 2020-7-28 11:00
     */
    public static Object fillTemplate(String template, String expressionPrefix, String expressionSuffix, Object rootObject) {
        Expression parse = parse(template, expressionPrefix, expressionSuffix);
        EvaluationContext context = context(rootObject, true);
        return parse.getValue(context);
    }


    public static class DevCenterElMapAccessor extends MapAccessor{
        @Override
        public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
            Assert.state(target instanceof Map, "Target must be of type Map");
            Map<?, ?> map = (Map<?, ?>) target;
            Object value = map.get(name);
            return new TypedValue(value);
        }
    }
}
